github.com/sean-/go@v0.0.0-20151219100004-97f854cd7bb6/src/cmd/compile/internal/gc/cplx.go (about) 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 5 package gc 6 7 import "cmd/internal/obj" 8 9 func overlap_cplx(f *Node, t *Node) bool { 10 // check whether f and t could be overlapping stack references. 11 // not exact, because it's hard to check for the stack register 12 // in portable code. close enough: worst case we will allocate 13 // an extra temporary and the registerizer will clean it up. 14 return f.Op == OINDREG && t.Op == OINDREG && f.Xoffset+f.Type.Width >= t.Xoffset && t.Xoffset+t.Type.Width >= f.Xoffset 15 } 16 17 func complexbool(op Op, nl, nr, res *Node, wantTrue bool, likely int, to *obj.Prog) { 18 // make both sides addable in ullman order 19 if nr != nil { 20 if nl.Ullman > nr.Ullman && !nl.Addable { 21 nl = CgenTemp(nl) 22 } 23 24 if !nr.Addable { 25 nr = CgenTemp(nr) 26 } 27 } 28 if !nl.Addable { 29 nl = CgenTemp(nl) 30 } 31 32 // Break nl and nr into real and imaginary components. 33 var lreal, limag, rreal, rimag Node 34 subnode(&lreal, &limag, nl) 35 subnode(&rreal, &rimag, nr) 36 37 // build tree 38 // if branching: 39 // real(l) == real(r) && imag(l) == imag(r) 40 // if generating a value, use a branch-free version: 41 // real(l) == real(r) & imag(l) == imag(r) 42 realeq := Node{ 43 Op: OEQ, 44 Left: &lreal, 45 Right: &rreal, 46 Type: Types[TBOOL], 47 } 48 imageq := Node{ 49 Op: OEQ, 50 Left: &limag, 51 Right: &rimag, 52 Type: Types[TBOOL], 53 } 54 and := Node{ 55 Op: OANDAND, 56 Left: &realeq, 57 Right: &imageq, 58 Type: Types[TBOOL], 59 } 60 61 if res != nil { 62 // generating a value 63 and.Op = OAND 64 if op == ONE { 65 and.Op = OOR 66 realeq.Op = ONE 67 imageq.Op = ONE 68 } 69 Bvgen(&and, res, true) 70 return 71 } 72 73 // generating a branch 74 if op == ONE { 75 wantTrue = !wantTrue 76 } 77 78 Bgen(&and, wantTrue, likely, to) 79 } 80 81 // break addable nc-complex into nr-real and ni-imaginary 82 func subnode(nr *Node, ni *Node, nc *Node) { 83 if !nc.Addable { 84 Fatalf("subnode not addable") 85 } 86 87 tc := Simsimtype(nc.Type) 88 tc = cplxsubtype(tc) 89 t := Types[tc] 90 91 if nc.Op == OLITERAL { 92 nodfconst(nr, t, &nc.Val().U.(*Mpcplx).Real) 93 nodfconst(ni, t, &nc.Val().U.(*Mpcplx).Imag) 94 return 95 } 96 97 *nr = *nc 98 nr.Type = t 99 100 *ni = *nc 101 ni.Type = t 102 ni.Xoffset += t.Width 103 } 104 105 // generate code res = -nl 106 func minus(nl *Node, res *Node) { 107 var ra Node 108 ra.Op = OMINUS 109 ra.Left = nl 110 ra.Type = nl.Type 111 Cgen(&ra, res) 112 } 113 114 // build and execute tree 115 // real(res) = -real(nl) 116 // imag(res) = -imag(nl) 117 func complexminus(nl *Node, res *Node) { 118 var n1 Node 119 var n2 Node 120 var n5 Node 121 var n6 Node 122 123 subnode(&n1, &n2, nl) 124 subnode(&n5, &n6, res) 125 126 minus(&n1, &n5) 127 minus(&n2, &n6) 128 } 129 130 // build and execute tree 131 // real(res) = real(nl) op real(nr) 132 // imag(res) = imag(nl) op imag(nr) 133 func complexadd(op Op, nl *Node, nr *Node, res *Node) { 134 var n1 Node 135 var n2 Node 136 var n3 Node 137 var n4 Node 138 var n5 Node 139 var n6 Node 140 141 subnode(&n1, &n2, nl) 142 subnode(&n3, &n4, nr) 143 subnode(&n5, &n6, res) 144 145 var ra Node 146 ra.Op = op 147 ra.Left = &n1 148 ra.Right = &n3 149 ra.Type = n1.Type 150 Cgen(&ra, &n5) 151 152 ra = Node{} 153 ra.Op = op 154 ra.Left = &n2 155 ra.Right = &n4 156 ra.Type = n2.Type 157 Cgen(&ra, &n6) 158 } 159 160 // build and execute tree 161 // tmp = real(nl)*real(nr) - imag(nl)*imag(nr) 162 // imag(res) = real(nl)*imag(nr) + imag(nl)*real(nr) 163 // real(res) = tmp 164 func complexmul(nl *Node, nr *Node, res *Node) { 165 var n1 Node 166 var n2 Node 167 var n3 Node 168 var n4 Node 169 var n5 Node 170 var n6 Node 171 var tmp Node 172 173 subnode(&n1, &n2, nl) 174 subnode(&n3, &n4, nr) 175 subnode(&n5, &n6, res) 176 Tempname(&tmp, n5.Type) 177 178 // real part -> tmp 179 var rm1 Node 180 181 rm1.Op = OMUL 182 rm1.Left = &n1 183 rm1.Right = &n3 184 rm1.Type = n1.Type 185 186 var rm2 Node 187 rm2.Op = OMUL 188 rm2.Left = &n2 189 rm2.Right = &n4 190 rm2.Type = n2.Type 191 192 var ra Node 193 ra.Op = OSUB 194 ra.Left = &rm1 195 ra.Right = &rm2 196 ra.Type = rm1.Type 197 Cgen(&ra, &tmp) 198 199 // imag part 200 rm1 = Node{} 201 202 rm1.Op = OMUL 203 rm1.Left = &n1 204 rm1.Right = &n4 205 rm1.Type = n1.Type 206 207 rm2 = Node{} 208 rm2.Op = OMUL 209 rm2.Left = &n2 210 rm2.Right = &n3 211 rm2.Type = n2.Type 212 213 ra = Node{} 214 ra.Op = OADD 215 ra.Left = &rm1 216 ra.Right = &rm2 217 ra.Type = rm1.Type 218 Cgen(&ra, &n6) 219 220 // tmp ->real part 221 Cgen(&tmp, &n5) 222 } 223 224 func nodfconst(n *Node, t *Type, fval *Mpflt) { 225 *n = Node{} 226 n.Op = OLITERAL 227 n.Addable = true 228 ullmancalc(n) 229 n.SetVal(Val{fval}) 230 n.Type = t 231 232 if !Isfloat[t.Etype] { 233 Fatalf("nodfconst: bad type %v", t) 234 } 235 } 236 237 func Complexop(n *Node, res *Node) bool { 238 if n != nil && n.Type != nil { 239 if Iscomplex[n.Type.Etype] { 240 goto maybe 241 } 242 } 243 244 if res != nil && res.Type != nil { 245 if Iscomplex[res.Type.Etype] { 246 goto maybe 247 } 248 } 249 250 if n.Op == OREAL || n.Op == OIMAG { 251 //dump("\ncomplex-yes", n); 252 return true 253 } 254 255 //dump("\ncomplex-no", n); 256 return false 257 258 maybe: 259 switch n.Op { 260 case OCONV, // implemented ops 261 OADD, 262 OSUB, 263 OMUL, 264 OMINUS, 265 OCOMPLEX, 266 OREAL, 267 OIMAG: 268 //dump("\ncomplex-yes", n); 269 return true 270 271 case ODOT, 272 ODOTPTR, 273 OINDEX, 274 OIND, 275 ONAME: 276 //dump("\ncomplex-yes", n); 277 return true 278 } 279 280 //dump("\ncomplex-no", n); 281 return false 282 } 283 284 func Complexmove(f *Node, t *Node) { 285 if Debug['g'] != 0 { 286 Dump("\ncomplexmove-f", f) 287 Dump("complexmove-t", t) 288 } 289 290 if !t.Addable { 291 Fatalf("complexmove: to not addable") 292 } 293 294 ft := Simsimtype(f.Type) 295 tt := Simsimtype(t.Type) 296 // complex to complex move/convert. 297 // make f addable. 298 // also use temporary if possible stack overlap. 299 if (ft == TCOMPLEX64 || ft == TCOMPLEX128) && (tt == TCOMPLEX64 || tt == TCOMPLEX128) { 300 if !f.Addable || overlap_cplx(f, t) { 301 var tmp Node 302 Tempname(&tmp, f.Type) 303 Complexmove(f, &tmp) 304 f = &tmp 305 } 306 307 var n1 Node 308 var n2 Node 309 subnode(&n1, &n2, f) 310 var n4 Node 311 var n3 Node 312 subnode(&n3, &n4, t) 313 314 Cgen(&n1, &n3) 315 Cgen(&n2, &n4) 316 } else { 317 Fatalf("complexmove: unknown conversion: %v -> %v\n", f.Type, t.Type) 318 } 319 } 320 321 func Complexgen(n *Node, res *Node) { 322 if Debug['g'] != 0 { 323 Dump("\ncomplexgen-n", n) 324 Dump("complexgen-res", res) 325 } 326 327 for n.Op == OCONVNOP { 328 n = n.Left 329 } 330 331 // pick off float/complex opcodes 332 switch n.Op { 333 case OCOMPLEX: 334 if res.Addable { 335 var n1 Node 336 var n2 Node 337 subnode(&n1, &n2, res) 338 var tmp Node 339 Tempname(&tmp, n1.Type) 340 Cgen(n.Left, &tmp) 341 Cgen(n.Right, &n2) 342 Cgen(&tmp, &n1) 343 return 344 } 345 346 case OREAL, OIMAG: 347 nl := n.Left 348 if !nl.Addable { 349 var tmp Node 350 Tempname(&tmp, nl.Type) 351 Complexgen(nl, &tmp) 352 nl = &tmp 353 } 354 355 var n1 Node 356 var n2 Node 357 subnode(&n1, &n2, nl) 358 if n.Op == OREAL { 359 Cgen(&n1, res) 360 return 361 } 362 363 Cgen(&n2, res) 364 return 365 } 366 367 // perform conversion from n to res 368 tl := Simsimtype(res.Type) 369 370 tl = cplxsubtype(tl) 371 tr := Simsimtype(n.Type) 372 tr = cplxsubtype(tr) 373 if tl != tr { 374 if !n.Addable { 375 var n1 Node 376 Tempname(&n1, n.Type) 377 Complexmove(n, &n1) 378 n = &n1 379 } 380 381 Complexmove(n, res) 382 return 383 } 384 385 if !res.Addable { 386 var n1 Node 387 Igen(res, &n1, nil) 388 Cgen(n, &n1) 389 Regfree(&n1) 390 return 391 } 392 393 if n.Addable { 394 Complexmove(n, res) 395 return 396 } 397 398 switch n.Op { 399 default: 400 Dump("complexgen: unknown op", n) 401 Fatalf("complexgen: unknown op %v", Oconv(int(n.Op), 0)) 402 403 case ODOT, 404 ODOTPTR, 405 OINDEX, 406 OIND, 407 ONAME, // PHEAP or PPARAMREF var 408 OCALLFUNC, 409 OCALLMETH, 410 OCALLINTER: 411 var n1 Node 412 Igen(n, &n1, res) 413 414 Complexmove(&n1, res) 415 Regfree(&n1) 416 return 417 418 case OCONV, 419 OADD, 420 OSUB, 421 OMUL, 422 OMINUS, 423 OCOMPLEX, 424 OREAL, 425 OIMAG: 426 break 427 } 428 429 nl := n.Left 430 if nl == nil { 431 return 432 } 433 nr := n.Right 434 435 // make both sides addable in ullman order 436 var tnl Node 437 if nr != nil { 438 if nl.Ullman > nr.Ullman && !nl.Addable { 439 Tempname(&tnl, nl.Type) 440 Cgen(nl, &tnl) 441 nl = &tnl 442 } 443 444 if !nr.Addable { 445 var tnr Node 446 Tempname(&tnr, nr.Type) 447 Cgen(nr, &tnr) 448 nr = &tnr 449 } 450 } 451 452 if !nl.Addable { 453 Tempname(&tnl, nl.Type) 454 Cgen(nl, &tnl) 455 nl = &tnl 456 } 457 458 switch n.Op { 459 default: 460 Fatalf("complexgen: unknown op %v", Oconv(int(n.Op), 0)) 461 462 case OCONV: 463 Complexmove(nl, res) 464 465 case OMINUS: 466 complexminus(nl, res) 467 468 case OADD, OSUB: 469 complexadd(n.Op, nl, nr, res) 470 471 case OMUL: 472 complexmul(nl, nr, res) 473 } 474 }