github.com/huandu/go@v0.0.0-20151114150818-04e615e41150/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 int, 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 Fatal("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 int, 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 = uint8(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 = uint8(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 Fatal("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 Fatal("complexmove: to not addable") 292 } 293 294 ft := Simsimtype(f.Type) 295 tt := Simsimtype(t.Type) 296 switch uint32(ft)<<16 | uint32(tt) { 297 default: 298 Fatal("complexmove: unknown conversion: %v -> %v\n", f.Type, t.Type) 299 300 // complex to complex move/convert. 301 // make f addable. 302 // also use temporary if possible stack overlap. 303 case TCOMPLEX64<<16 | TCOMPLEX64, 304 TCOMPLEX64<<16 | TCOMPLEX128, 305 TCOMPLEX128<<16 | TCOMPLEX64, 306 TCOMPLEX128<<16 | TCOMPLEX128: 307 if !f.Addable || overlap_cplx(f, t) { 308 var tmp Node 309 Tempname(&tmp, f.Type) 310 Complexmove(f, &tmp) 311 f = &tmp 312 } 313 314 var n1 Node 315 var n2 Node 316 subnode(&n1, &n2, f) 317 var n4 Node 318 var n3 Node 319 subnode(&n3, &n4, t) 320 321 Cgen(&n1, &n3) 322 Cgen(&n2, &n4) 323 } 324 } 325 326 func Complexgen(n *Node, res *Node) { 327 if Debug['g'] != 0 { 328 Dump("\ncomplexgen-n", n) 329 Dump("complexgen-res", res) 330 } 331 332 for n.Op == OCONVNOP { 333 n = n.Left 334 } 335 336 // pick off float/complex opcodes 337 switch n.Op { 338 case OCOMPLEX: 339 if res.Addable { 340 var n1 Node 341 var n2 Node 342 subnode(&n1, &n2, res) 343 var tmp Node 344 Tempname(&tmp, n1.Type) 345 Cgen(n.Left, &tmp) 346 Cgen(n.Right, &n2) 347 Cgen(&tmp, &n1) 348 return 349 } 350 351 case OREAL, OIMAG: 352 nl := n.Left 353 if !nl.Addable { 354 var tmp Node 355 Tempname(&tmp, nl.Type) 356 Complexgen(nl, &tmp) 357 nl = &tmp 358 } 359 360 var n1 Node 361 var n2 Node 362 subnode(&n1, &n2, nl) 363 if n.Op == OREAL { 364 Cgen(&n1, res) 365 return 366 } 367 368 Cgen(&n2, res) 369 return 370 } 371 372 // perform conversion from n to res 373 tl := Simsimtype(res.Type) 374 375 tl = cplxsubtype(tl) 376 tr := Simsimtype(n.Type) 377 tr = cplxsubtype(tr) 378 if tl != tr { 379 if !n.Addable { 380 var n1 Node 381 Tempname(&n1, n.Type) 382 Complexmove(n, &n1) 383 n = &n1 384 } 385 386 Complexmove(n, res) 387 return 388 } 389 390 if !res.Addable { 391 var n1 Node 392 Igen(res, &n1, nil) 393 Cgen(n, &n1) 394 Regfree(&n1) 395 return 396 } 397 398 if n.Addable { 399 Complexmove(n, res) 400 return 401 } 402 403 switch n.Op { 404 default: 405 Dump("complexgen: unknown op", n) 406 Fatal("complexgen: unknown op %v", Oconv(int(n.Op), 0)) 407 408 case ODOT, 409 ODOTPTR, 410 OINDEX, 411 OIND, 412 ONAME, // PHEAP or PPARAMREF var 413 OCALLFUNC, 414 OCALLMETH, 415 OCALLINTER: 416 var n1 Node 417 Igen(n, &n1, res) 418 419 Complexmove(&n1, res) 420 Regfree(&n1) 421 return 422 423 case OCONV, 424 OADD, 425 OSUB, 426 OMUL, 427 OMINUS, 428 OCOMPLEX, 429 OREAL, 430 OIMAG: 431 break 432 } 433 434 nl := n.Left 435 if nl == nil { 436 return 437 } 438 nr := n.Right 439 440 // make both sides addable in ullman order 441 var tnl Node 442 if nr != nil { 443 if nl.Ullman > nr.Ullman && !nl.Addable { 444 Tempname(&tnl, nl.Type) 445 Cgen(nl, &tnl) 446 nl = &tnl 447 } 448 449 if !nr.Addable { 450 var tnr Node 451 Tempname(&tnr, nr.Type) 452 Cgen(nr, &tnr) 453 nr = &tnr 454 } 455 } 456 457 if !nl.Addable { 458 Tempname(&tnl, nl.Type) 459 Cgen(nl, &tnl) 460 nl = &tnl 461 } 462 463 switch n.Op { 464 default: 465 Fatal("complexgen: unknown op %v", Oconv(int(n.Op), 0)) 466 467 case OCONV: 468 Complexmove(nl, res) 469 470 case OMINUS: 471 complexminus(nl, res) 472 473 case OADD, OSUB: 474 complexadd(int(n.Op), nl, nr, res) 475 476 case OMUL: 477 complexmul(nl, nr, res) 478 } 479 }