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