github.com/euank/go@v0.0.0-20160829210321-495514729181/src/cmd/compile/internal/ppc64/gsubr.go (about) 1 // Derived from Inferno utils/6c/txt.c 2 // https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6c/txt.c 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 6 // Portions Copyright © 1997-1999 Vita Nuova Limited 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) 8 // Portions Copyright © 2004,2006 Bruce Ellis 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 11 // Portions Copyright © 2009 The Go Authors. All rights reserved. 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a copy 14 // of this software and associated documentation files (the "Software"), to deal 15 // in the Software without restriction, including without limitation the rights 16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 // copies of the Software, and to permit persons to whom the Software is 18 // furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included in 21 // all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 // THE SOFTWARE. 30 31 package ppc64 32 33 import ( 34 "cmd/compile/internal/big" 35 "cmd/compile/internal/gc" 36 "cmd/internal/obj" 37 "cmd/internal/obj/ppc64" 38 "fmt" 39 ) 40 41 var resvd = []int{ 42 ppc64.REGZERO, 43 ppc64.REGSP, // reserved for SP 44 // We need to preserve the C ABI TLS pointer because sigtramp 45 // may happen during C code and needs to access the g. C 46 // clobbers REGG, so if Go were to clobber REGTLS, sigtramp 47 // won't know which convention to use. By preserving REGTLS, 48 // we can just retrieve g from TLS when we aren't sure. 49 ppc64.REGTLS, 50 51 // TODO(austin): Consolidate REGTLS and REGG? 52 ppc64.REGG, 53 ppc64.REGTMP, // REGTMP 54 ppc64.FREGCVI, 55 ppc64.FREGZERO, 56 ppc64.FREGHALF, 57 ppc64.FREGONE, 58 ppc64.FREGTWO, 59 } 60 61 /* 62 * generate 63 * as $c, n 64 */ 65 func ginscon(as obj.As, c int64, n2 *gc.Node) { 66 var n1 gc.Node 67 68 gc.Nodconst(&n1, gc.Types[gc.TINT64], c) 69 70 if as != ppc64.AMOVD && (c < -ppc64.BIG || c > ppc64.BIG) || n2.Op != gc.OREGISTER || as == ppc64.AMULLD { 71 // cannot have more than 16-bit of immediate in ADD, etc. 72 // instead, MOV into register first. 73 var ntmp gc.Node 74 gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil) 75 76 rawgins(ppc64.AMOVD, &n1, &ntmp) 77 rawgins(as, &ntmp, n2) 78 gc.Regfree(&ntmp) 79 return 80 } 81 82 rawgins(as, &n1, n2) 83 } 84 85 /* 86 * generate 87 * as n, $c (CMP/CMPU) 88 */ 89 func ginscon2(as obj.As, n2 *gc.Node, c int64) { 90 var n1 gc.Node 91 92 gc.Nodconst(&n1, gc.Types[gc.TINT64], c) 93 94 switch as { 95 default: 96 gc.Fatalf("ginscon2") 97 98 case ppc64.ACMP: 99 if -ppc64.BIG <= c && c <= ppc64.BIG { 100 rawgins(as, n2, &n1) 101 return 102 } 103 104 case ppc64.ACMPU: 105 if 0 <= c && c <= 2*ppc64.BIG { 106 rawgins(as, n2, &n1) 107 return 108 } 109 } 110 111 // MOV n1 into register first 112 var ntmp gc.Node 113 gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil) 114 115 rawgins(ppc64.AMOVD, &n1, &ntmp) 116 rawgins(as, n2, &ntmp) 117 gc.Regfree(&ntmp) 118 } 119 120 func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog { 121 if t.IsInteger() && n1.Op == gc.OLITERAL && n2.Op != gc.OLITERAL { 122 // Reverse comparison to place constant last. 123 op = gc.Brrev(op) 124 n1, n2 = n2, n1 125 } 126 127 var r1, r2, g1, g2 gc.Node 128 gc.Regalloc(&r1, t, n1) 129 gc.Regalloc(&g1, n1.Type, &r1) 130 gc.Cgen(n1, &g1) 131 gmove(&g1, &r1) 132 if t.IsInteger() && gc.Isconst(n2, gc.CTINT) { 133 ginscon2(optoas(gc.OCMP, t), &r1, n2.Int64()) 134 } else { 135 gc.Regalloc(&r2, t, n2) 136 gc.Regalloc(&g2, n1.Type, &r2) 137 gc.Cgen(n2, &g2) 138 gmove(&g2, &r2) 139 rawgins(optoas(gc.OCMP, t), &r1, &r2) 140 gc.Regfree(&g2) 141 gc.Regfree(&r2) 142 } 143 gc.Regfree(&g1) 144 gc.Regfree(&r1) 145 return gc.Gbranch(optoas(op, t), nil, likely) 146 } 147 148 // set up nodes representing 2^63 149 var ( 150 bigi gc.Node 151 bigf gc.Node 152 bignodes_did bool 153 ) 154 155 func bignodes() { 156 if bignodes_did { 157 return 158 } 159 bignodes_did = true 160 161 var i big.Int 162 i.SetInt64(1) 163 i.Lsh(&i, 63) 164 165 gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0) 166 bigi.SetBigInt(&i) 167 168 bigi.Convconst(&bigf, gc.Types[gc.TFLOAT64]) 169 } 170 171 /* 172 * generate move: 173 * t = f 174 * hard part is conversions. 175 */ 176 func gmove(f *gc.Node, t *gc.Node) { 177 if gc.Debug['M'] != 0 { 178 fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, gc.FmtLong), gc.Nconv(t, gc.FmtLong)) 179 } 180 181 ft := int(gc.Simsimtype(f.Type)) 182 tt := int(gc.Simsimtype(t.Type)) 183 cvt := t.Type 184 185 if gc.Iscomplex[ft] || gc.Iscomplex[tt] { 186 gc.Complexmove(f, t) 187 return 188 } 189 190 // cannot have two memory operands 191 var r2 gc.Node 192 var r1 gc.Node 193 var a obj.As 194 if gc.Ismem(f) && gc.Ismem(t) { 195 goto hard 196 } 197 198 // convert constant to desired type 199 if f.Op == gc.OLITERAL { 200 var con gc.Node 201 switch tt { 202 default: 203 f.Convconst(&con, t.Type) 204 205 case gc.TINT32, 206 gc.TINT16, 207 gc.TINT8: 208 var con gc.Node 209 f.Convconst(&con, gc.Types[gc.TINT64]) 210 var r1 gc.Node 211 gc.Regalloc(&r1, con.Type, t) 212 gins(ppc64.AMOVD, &con, &r1) 213 gmove(&r1, t) 214 gc.Regfree(&r1) 215 return 216 217 case gc.TUINT32, 218 gc.TUINT16, 219 gc.TUINT8: 220 var con gc.Node 221 f.Convconst(&con, gc.Types[gc.TUINT64]) 222 var r1 gc.Node 223 gc.Regalloc(&r1, con.Type, t) 224 gins(ppc64.AMOVD, &con, &r1) 225 gmove(&r1, t) 226 gc.Regfree(&r1) 227 return 228 } 229 230 f = &con 231 ft = tt // so big switch will choose a simple mov 232 233 // constants can't move directly to memory. 234 if gc.Ismem(t) { 235 goto hard 236 } 237 } 238 239 // float constants come from memory. 240 //if(isfloat[tt]) 241 // goto hard; 242 243 // 64-bit immediates are also from memory. 244 //if(isint[tt]) 245 // goto hard; 246 //// 64-bit immediates are really 32-bit sign-extended 247 //// unless moving into a register. 248 //if(isint[tt]) { 249 // if(mpcmpfixfix(con.val.u.xval, minintval[TINT32]) < 0) 250 // goto hard; 251 // if(mpcmpfixfix(con.val.u.xval, maxintval[TINT32]) > 0) 252 // goto hard; 253 //} 254 255 // value -> value copy, only one memory operand. 256 // figure out the instruction to use. 257 // break out of switch for one-instruction gins. 258 // goto rdst for "destination must be register". 259 // goto hard for "convert to cvt type first". 260 // otherwise handle and return. 261 262 switch uint32(ft)<<16 | uint32(tt) { 263 default: 264 gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, gc.FmtLong), gc.Tconv(t.Type, gc.FmtLong)) 265 266 /* 267 * integer copy and truncate 268 */ 269 case gc.TINT8<<16 | gc.TINT8, // same size 270 gc.TUINT8<<16 | gc.TINT8, 271 gc.TINT16<<16 | gc.TINT8, 272 // truncate 273 gc.TUINT16<<16 | gc.TINT8, 274 gc.TINT32<<16 | gc.TINT8, 275 gc.TUINT32<<16 | gc.TINT8, 276 gc.TINT64<<16 | gc.TINT8, 277 gc.TUINT64<<16 | gc.TINT8: 278 a = ppc64.AMOVB 279 280 case gc.TINT8<<16 | gc.TUINT8, // same size 281 gc.TUINT8<<16 | gc.TUINT8, 282 gc.TINT16<<16 | gc.TUINT8, 283 // truncate 284 gc.TUINT16<<16 | gc.TUINT8, 285 gc.TINT32<<16 | gc.TUINT8, 286 gc.TUINT32<<16 | gc.TUINT8, 287 gc.TINT64<<16 | gc.TUINT8, 288 gc.TUINT64<<16 | gc.TUINT8: 289 a = ppc64.AMOVBZ 290 291 case gc.TINT16<<16 | gc.TINT16, // same size 292 gc.TUINT16<<16 | gc.TINT16, 293 gc.TINT32<<16 | gc.TINT16, 294 // truncate 295 gc.TUINT32<<16 | gc.TINT16, 296 gc.TINT64<<16 | gc.TINT16, 297 gc.TUINT64<<16 | gc.TINT16: 298 a = ppc64.AMOVH 299 300 case gc.TINT16<<16 | gc.TUINT16, // same size 301 gc.TUINT16<<16 | gc.TUINT16, 302 gc.TINT32<<16 | gc.TUINT16, 303 // truncate 304 gc.TUINT32<<16 | gc.TUINT16, 305 gc.TINT64<<16 | gc.TUINT16, 306 gc.TUINT64<<16 | gc.TUINT16: 307 a = ppc64.AMOVHZ 308 309 case gc.TINT32<<16 | gc.TINT32, // same size 310 gc.TUINT32<<16 | gc.TINT32, 311 gc.TINT64<<16 | gc.TINT32, 312 // truncate 313 gc.TUINT64<<16 | gc.TINT32: 314 a = ppc64.AMOVW 315 316 case gc.TINT32<<16 | gc.TUINT32, // same size 317 gc.TUINT32<<16 | gc.TUINT32, 318 gc.TINT64<<16 | gc.TUINT32, 319 gc.TUINT64<<16 | gc.TUINT32: 320 a = ppc64.AMOVWZ 321 322 case gc.TINT64<<16 | gc.TINT64, // same size 323 gc.TINT64<<16 | gc.TUINT64, 324 gc.TUINT64<<16 | gc.TINT64, 325 gc.TUINT64<<16 | gc.TUINT64: 326 a = ppc64.AMOVD 327 328 /* 329 * integer up-conversions 330 */ 331 case gc.TINT8<<16 | gc.TINT16, // sign extend int8 332 gc.TINT8<<16 | gc.TUINT16, 333 gc.TINT8<<16 | gc.TINT32, 334 gc.TINT8<<16 | gc.TUINT32, 335 gc.TINT8<<16 | gc.TINT64, 336 gc.TINT8<<16 | gc.TUINT64: 337 a = ppc64.AMOVB 338 339 goto rdst 340 341 case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8 342 gc.TUINT8<<16 | gc.TUINT16, 343 gc.TUINT8<<16 | gc.TINT32, 344 gc.TUINT8<<16 | gc.TUINT32, 345 gc.TUINT8<<16 | gc.TINT64, 346 gc.TUINT8<<16 | gc.TUINT64: 347 a = ppc64.AMOVBZ 348 349 goto rdst 350 351 case gc.TINT16<<16 | gc.TINT32, // sign extend int16 352 gc.TINT16<<16 | gc.TUINT32, 353 gc.TINT16<<16 | gc.TINT64, 354 gc.TINT16<<16 | gc.TUINT64: 355 a = ppc64.AMOVH 356 357 goto rdst 358 359 case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16 360 gc.TUINT16<<16 | gc.TUINT32, 361 gc.TUINT16<<16 | gc.TINT64, 362 gc.TUINT16<<16 | gc.TUINT64: 363 a = ppc64.AMOVHZ 364 365 goto rdst 366 367 case gc.TINT32<<16 | gc.TINT64, // sign extend int32 368 gc.TINT32<<16 | gc.TUINT64: 369 a = ppc64.AMOVW 370 371 goto rdst 372 373 case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32 374 gc.TUINT32<<16 | gc.TUINT64: 375 a = ppc64.AMOVWZ 376 377 goto rdst 378 379 //warn("gmove: convert float to int not implemented: %N -> %N\n", f, t); 380 //return; 381 // algorithm is: 382 // if small enough, use native float64 -> int64 conversion. 383 // otherwise, subtract 2^63, convert, and add it back. 384 /* 385 * float to integer 386 */ 387 case gc.TFLOAT32<<16 | gc.TINT32, 388 gc.TFLOAT64<<16 | gc.TINT32, 389 gc.TFLOAT32<<16 | gc.TINT64, 390 gc.TFLOAT64<<16 | gc.TINT64, 391 gc.TFLOAT32<<16 | gc.TINT16, 392 gc.TFLOAT32<<16 | gc.TINT8, 393 gc.TFLOAT32<<16 | gc.TUINT16, 394 gc.TFLOAT32<<16 | gc.TUINT8, 395 gc.TFLOAT64<<16 | gc.TINT16, 396 gc.TFLOAT64<<16 | gc.TINT8, 397 gc.TFLOAT64<<16 | gc.TUINT16, 398 gc.TFLOAT64<<16 | gc.TUINT8, 399 gc.TFLOAT32<<16 | gc.TUINT32, 400 gc.TFLOAT64<<16 | gc.TUINT32, 401 gc.TFLOAT32<<16 | gc.TUINT64, 402 gc.TFLOAT64<<16 | gc.TUINT64: 403 bignodes() 404 405 var r1 gc.Node 406 gc.Regalloc(&r1, gc.Types[ft], f) 407 gmove(f, &r1) 408 if tt == gc.TUINT64 { 409 gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], nil) 410 gmove(&bigf, &r2) 411 gins(ppc64.AFCMPU, &r1, &r2) 412 p1 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TFLOAT64]), nil, +1) 413 gins(ppc64.AFSUB, &r2, &r1) 414 gc.Patch(p1, gc.Pc) 415 gc.Regfree(&r2) 416 } 417 418 gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], nil) 419 var r3 gc.Node 420 gc.Regalloc(&r3, gc.Types[gc.TINT64], t) 421 gins(ppc64.AFCTIDZ, &r1, &r2) 422 p1 := gins(ppc64.AFMOVD, &r2, nil) 423 p1.To.Type = obj.TYPE_MEM 424 p1.To.Reg = ppc64.REGSP 425 p1.To.Offset = -8 426 p1 = gins(ppc64.AMOVD, nil, &r3) 427 p1.From.Type = obj.TYPE_MEM 428 p1.From.Reg = ppc64.REGSP 429 p1.From.Offset = -8 430 gc.Regfree(&r2) 431 gc.Regfree(&r1) 432 if tt == gc.TUINT64 { 433 p1 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TFLOAT64]), nil, +1) // use CR0 here again 434 gc.Nodreg(&r1, gc.Types[gc.TINT64], ppc64.REGTMP) 435 gins(ppc64.AMOVD, &bigi, &r1) 436 gins(ppc64.AADD, &r1, &r3) 437 gc.Patch(p1, gc.Pc) 438 } 439 440 gmove(&r3, t) 441 gc.Regfree(&r3) 442 return 443 444 /* 445 * integer to float 446 */ 447 case gc.TINT32<<16 | gc.TFLOAT32, 448 gc.TINT32<<16 | gc.TFLOAT64, 449 gc.TINT64<<16 | gc.TFLOAT32, 450 gc.TINT64<<16 | gc.TFLOAT64, 451 gc.TINT16<<16 | gc.TFLOAT32, 452 gc.TINT16<<16 | gc.TFLOAT64, 453 gc.TINT8<<16 | gc.TFLOAT32, 454 gc.TINT8<<16 | gc.TFLOAT64, 455 gc.TUINT16<<16 | gc.TFLOAT32, 456 gc.TUINT16<<16 | gc.TFLOAT64, 457 gc.TUINT8<<16 | gc.TFLOAT32, 458 gc.TUINT8<<16 | gc.TFLOAT64, 459 gc.TUINT32<<16 | gc.TFLOAT32, 460 gc.TUINT32<<16 | gc.TFLOAT64, 461 gc.TUINT64<<16 | gc.TFLOAT32, 462 gc.TUINT64<<16 | gc.TFLOAT64: 463 bignodes() 464 465 // The algorithm is: 466 // if small enough, use native int64 -> float64 conversion, 467 // otherwise halve (x -> (x>>1)|(x&1)), convert, and double. 468 // Note: could use FCFIDU instead if target supports it. 469 var r1 gc.Node 470 gc.Regalloc(&r1, gc.Types[gc.TINT64], nil) 471 gmove(f, &r1) 472 if ft == gc.TUINT64 { 473 gc.Nodreg(&r2, gc.Types[gc.TUINT64], ppc64.REGTMP) 474 gmove(&bigi, &r2) 475 gins(ppc64.ACMPU, &r1, &r2) 476 p1 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT64]), nil, +1) 477 var r3 gc.Node 478 gc.Regalloc(&r3, gc.Types[gc.TUINT64], nil) 479 p2 := gins(ppc64.AANDCC, nil, &r3) // andi. 480 p2.Reg = r1.Reg 481 p2.From.Type = obj.TYPE_CONST 482 p2.From.Offset = 1 483 p3 := gins(ppc64.ASRD, nil, &r1) 484 p3.From.Type = obj.TYPE_CONST 485 p3.From.Offset = 1 486 gins(ppc64.AOR, &r3, &r1) 487 gc.Regfree(&r3) 488 gc.Patch(p1, gc.Pc) 489 } 490 gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], t) 491 p1 := gins(ppc64.AMOVD, &r1, nil) 492 p1.To.Type = obj.TYPE_MEM 493 p1.To.Reg = ppc64.REGSP 494 p1.To.Offset = -8 495 p1 = gins(ppc64.AFMOVD, nil, &r2) 496 p1.From.Type = obj.TYPE_MEM 497 p1.From.Reg = ppc64.REGSP 498 p1.From.Offset = -8 499 gins(ppc64.AFCFID, &r2, &r2) 500 gc.Regfree(&r1) 501 if ft == gc.TUINT64 { 502 p1 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT64]), nil, +1) // use CR0 here again 503 gc.Nodreg(&r1, gc.Types[gc.TFLOAT64], ppc64.FREGTWO) 504 gins(ppc64.AFMUL, &r1, &r2) 505 gc.Patch(p1, gc.Pc) 506 } 507 gmove(&r2, t) 508 gc.Regfree(&r2) 509 return 510 511 /* 512 * float to float 513 */ 514 case gc.TFLOAT32<<16 | gc.TFLOAT32: 515 a = ppc64.AFMOVS 516 517 case gc.TFLOAT64<<16 | gc.TFLOAT64: 518 a = ppc64.AFMOVD 519 520 case gc.TFLOAT32<<16 | gc.TFLOAT64: 521 a = ppc64.AFMOVS 522 goto rdst 523 524 case gc.TFLOAT64<<16 | gc.TFLOAT32: 525 a = ppc64.AFRSP 526 goto rdst 527 } 528 529 gins(a, f, t) 530 return 531 532 // requires register destination 533 rdst: 534 { 535 gc.Regalloc(&r1, t.Type, t) 536 537 gins(a, f, &r1) 538 gmove(&r1, t) 539 gc.Regfree(&r1) 540 return 541 } 542 543 // requires register intermediate 544 hard: 545 gc.Regalloc(&r1, cvt, t) 546 547 gmove(f, &r1) 548 gmove(&r1, t) 549 gc.Regfree(&r1) 550 return 551 } 552 553 // gins is called by the front end. 554 // It synthesizes some multiple-instruction sequences 555 // so the front end can stay simpler. 556 func gins(as obj.As, f, t *gc.Node) *obj.Prog { 557 if as >= obj.A_ARCHSPECIFIC { 558 if x, ok := f.IntLiteral(); ok { 559 ginscon(as, x, t) 560 return nil // caller must not use 561 } 562 } 563 if as == ppc64.ACMP || as == ppc64.ACMPU { 564 if x, ok := t.IntLiteral(); ok { 565 ginscon2(as, f, x) 566 return nil // caller must not use 567 } 568 } 569 return rawgins(as, f, t) 570 } 571 572 /* 573 * generate one instruction: 574 * as f, t 575 */ 576 func rawgins(as obj.As, f *gc.Node, t *gc.Node) *obj.Prog { 577 // TODO(austin): Add self-move test like in 6g (but be careful 578 // of truncation moves) 579 580 p := gc.Prog(as) 581 gc.Naddr(&p.From, f) 582 gc.Naddr(&p.To, t) 583 584 switch as { 585 case obj.ACALL: 586 if p.To.Type == obj.TYPE_REG && p.To.Reg != ppc64.REG_CTR { 587 // Allow front end to emit CALL REG, and rewrite into MOV REG, CTR; CALL CTR. 588 if gc.Ctxt.Flag_shared { 589 // Make sure function pointer is in R12 as well when 590 // compiling Go into PIC. 591 // TODO(mwhudson): it would obviously be better to 592 // change the register allocation to put the value in 593 // R12 already, but I don't know how to do that. 594 q := gc.Prog(as) 595 q.As = ppc64.AMOVD 596 q.From = p.To 597 q.To.Type = obj.TYPE_REG 598 q.To.Reg = ppc64.REG_R12 599 } 600 pp := gc.Prog(as) 601 pp.From = p.From 602 pp.To.Type = obj.TYPE_REG 603 pp.To.Reg = ppc64.REG_CTR 604 605 p.As = ppc64.AMOVD 606 p.From = p.To 607 p.To.Type = obj.TYPE_REG 608 p.To.Reg = ppc64.REG_CTR 609 610 if gc.Ctxt.Flag_shared { 611 // When compiling Go into PIC, the function we just 612 // called via pointer might have been implemented in 613 // a separate module and so overwritten the TOC 614 // pointer in R2; reload it. 615 q := gc.Prog(ppc64.AMOVD) 616 q.From.Type = obj.TYPE_MEM 617 q.From.Offset = 24 618 q.From.Reg = ppc64.REGSP 619 q.To.Type = obj.TYPE_REG 620 q.To.Reg = ppc64.REG_R2 621 } 622 623 if gc.Debug['g'] != 0 { 624 fmt.Printf("%v\n", p) 625 fmt.Printf("%v\n", pp) 626 } 627 628 return pp 629 } 630 631 // Bad things the front end has done to us. Crash to find call stack. 632 case ppc64.AAND, ppc64.AMULLD: 633 if p.From.Type == obj.TYPE_CONST { 634 gc.Debug['h'] = 1 635 gc.Fatalf("bad inst: %v", p) 636 } 637 case ppc64.ACMP, ppc64.ACMPU: 638 if p.From.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_MEM { 639 gc.Debug['h'] = 1 640 gc.Fatalf("bad inst: %v", p) 641 } 642 } 643 644 if gc.Debug['g'] != 0 { 645 fmt.Printf("%v\n", p) 646 } 647 648 w := int32(0) 649 switch as { 650 case ppc64.AMOVB, 651 ppc64.AMOVBU, 652 ppc64.AMOVBZ, 653 ppc64.AMOVBZU: 654 w = 1 655 656 case ppc64.AMOVH, 657 ppc64.AMOVHU, 658 ppc64.AMOVHZ, 659 ppc64.AMOVHZU: 660 w = 2 661 662 case ppc64.AMOVW, 663 ppc64.AMOVWU, 664 ppc64.AMOVWZ, 665 ppc64.AMOVWZU: 666 w = 4 667 668 case ppc64.AMOVD, 669 ppc64.AMOVDU: 670 if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_ADDR { 671 break 672 } 673 w = 8 674 } 675 676 if w != 0 && ((f != nil && p.From.Width < int64(w)) || (t != nil && p.To.Type != obj.TYPE_REG && p.To.Width > int64(w))) { 677 gc.Dump("f", f) 678 gc.Dump("t", t) 679 gc.Fatalf("bad width: %v (%d, %d)\n", p, p.From.Width, p.To.Width) 680 } 681 682 return p 683 } 684 685 /* 686 * return Axxx for Oxxx on type t. 687 */ 688 func optoas(op gc.Op, t *gc.Type) obj.As { 689 if t == nil { 690 gc.Fatalf("optoas: t is nil") 691 } 692 693 // avoid constant conversions in switches below 694 const ( 695 OMINUS_ = uint32(gc.OMINUS) << 16 696 OLSH_ = uint32(gc.OLSH) << 16 697 ORSH_ = uint32(gc.ORSH) << 16 698 OADD_ = uint32(gc.OADD) << 16 699 OSUB_ = uint32(gc.OSUB) << 16 700 OMUL_ = uint32(gc.OMUL) << 16 701 ODIV_ = uint32(gc.ODIV) << 16 702 OOR_ = uint32(gc.OOR) << 16 703 OAND_ = uint32(gc.OAND) << 16 704 OXOR_ = uint32(gc.OXOR) << 16 705 OEQ_ = uint32(gc.OEQ) << 16 706 ONE_ = uint32(gc.ONE) << 16 707 OLT_ = uint32(gc.OLT) << 16 708 OLE_ = uint32(gc.OLE) << 16 709 OGE_ = uint32(gc.OGE) << 16 710 OGT_ = uint32(gc.OGT) << 16 711 OCMP_ = uint32(gc.OCMP) << 16 712 OAS_ = uint32(gc.OAS) << 16 713 OHMUL_ = uint32(gc.OHMUL) << 16 714 OSQRT_ = uint32(gc.OSQRT) << 16 715 ) 716 717 a := obj.AXXX 718 switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) { 719 default: 720 gc.Fatalf("optoas: no entry for op=%v type=%v", op, t) 721 722 case OEQ_ | gc.TBOOL, 723 OEQ_ | gc.TINT8, 724 OEQ_ | gc.TUINT8, 725 OEQ_ | gc.TINT16, 726 OEQ_ | gc.TUINT16, 727 OEQ_ | gc.TINT32, 728 OEQ_ | gc.TUINT32, 729 OEQ_ | gc.TINT64, 730 OEQ_ | gc.TUINT64, 731 OEQ_ | gc.TPTR32, 732 OEQ_ | gc.TPTR64, 733 OEQ_ | gc.TFLOAT32, 734 OEQ_ | gc.TFLOAT64: 735 a = ppc64.ABEQ 736 737 case ONE_ | gc.TBOOL, 738 ONE_ | gc.TINT8, 739 ONE_ | gc.TUINT8, 740 ONE_ | gc.TINT16, 741 ONE_ | gc.TUINT16, 742 ONE_ | gc.TINT32, 743 ONE_ | gc.TUINT32, 744 ONE_ | gc.TINT64, 745 ONE_ | gc.TUINT64, 746 ONE_ | gc.TPTR32, 747 ONE_ | gc.TPTR64, 748 ONE_ | gc.TFLOAT32, 749 ONE_ | gc.TFLOAT64: 750 a = ppc64.ABNE 751 752 case OLT_ | gc.TINT8, // ACMP 753 OLT_ | gc.TINT16, 754 OLT_ | gc.TINT32, 755 OLT_ | gc.TINT64, 756 OLT_ | gc.TUINT8, 757 // ACMPU 758 OLT_ | gc.TUINT16, 759 OLT_ | gc.TUINT32, 760 OLT_ | gc.TUINT64, 761 OLT_ | gc.TFLOAT32, 762 // AFCMPU 763 OLT_ | gc.TFLOAT64: 764 a = ppc64.ABLT 765 766 case OLE_ | gc.TINT8, // ACMP 767 OLE_ | gc.TINT16, 768 OLE_ | gc.TINT32, 769 OLE_ | gc.TINT64, 770 OLE_ | gc.TUINT8, 771 // ACMPU 772 OLE_ | gc.TUINT16, 773 OLE_ | gc.TUINT32, 774 OLE_ | gc.TUINT64: 775 // No OLE for floats, because it mishandles NaN. 776 // Front end must reverse comparison or use OLT and OEQ together. 777 a = ppc64.ABLE 778 779 case OGT_ | gc.TINT8, 780 OGT_ | gc.TINT16, 781 OGT_ | gc.TINT32, 782 OGT_ | gc.TINT64, 783 OGT_ | gc.TUINT8, 784 OGT_ | gc.TUINT16, 785 OGT_ | gc.TUINT32, 786 OGT_ | gc.TUINT64, 787 OGT_ | gc.TFLOAT32, 788 OGT_ | gc.TFLOAT64: 789 a = ppc64.ABGT 790 791 case OGE_ | gc.TINT8, 792 OGE_ | gc.TINT16, 793 OGE_ | gc.TINT32, 794 OGE_ | gc.TINT64, 795 OGE_ | gc.TUINT8, 796 OGE_ | gc.TUINT16, 797 OGE_ | gc.TUINT32, 798 OGE_ | gc.TUINT64: 799 // No OGE for floats, because it mishandles NaN. 800 // Front end must reverse comparison or use OLT and OEQ together. 801 a = ppc64.ABGE 802 803 case OCMP_ | gc.TBOOL, 804 OCMP_ | gc.TINT8, 805 OCMP_ | gc.TINT16, 806 OCMP_ | gc.TINT32, 807 OCMP_ | gc.TPTR32, 808 OCMP_ | gc.TINT64: 809 a = ppc64.ACMP 810 811 case OCMP_ | gc.TUINT8, 812 OCMP_ | gc.TUINT16, 813 OCMP_ | gc.TUINT32, 814 OCMP_ | gc.TUINT64, 815 OCMP_ | gc.TPTR64: 816 a = ppc64.ACMPU 817 818 case OCMP_ | gc.TFLOAT32, 819 OCMP_ | gc.TFLOAT64: 820 a = ppc64.AFCMPU 821 822 case OAS_ | gc.TBOOL, 823 OAS_ | gc.TINT8: 824 a = ppc64.AMOVB 825 826 case OAS_ | gc.TUINT8: 827 a = ppc64.AMOVBZ 828 829 case OAS_ | gc.TINT16: 830 a = ppc64.AMOVH 831 832 case OAS_ | gc.TUINT16: 833 a = ppc64.AMOVHZ 834 835 case OAS_ | gc.TINT32: 836 a = ppc64.AMOVW 837 838 case OAS_ | gc.TUINT32, 839 OAS_ | gc.TPTR32: 840 a = ppc64.AMOVWZ 841 842 case OAS_ | gc.TINT64, 843 OAS_ | gc.TUINT64, 844 OAS_ | gc.TPTR64: 845 a = ppc64.AMOVD 846 847 case OAS_ | gc.TFLOAT32: 848 a = ppc64.AFMOVS 849 850 case OAS_ | gc.TFLOAT64: 851 a = ppc64.AFMOVD 852 853 case OADD_ | gc.TINT8, 854 OADD_ | gc.TUINT8, 855 OADD_ | gc.TINT16, 856 OADD_ | gc.TUINT16, 857 OADD_ | gc.TINT32, 858 OADD_ | gc.TUINT32, 859 OADD_ | gc.TPTR32, 860 OADD_ | gc.TINT64, 861 OADD_ | gc.TUINT64, 862 OADD_ | gc.TPTR64: 863 a = ppc64.AADD 864 865 case OADD_ | gc.TFLOAT32: 866 a = ppc64.AFADDS 867 868 case OADD_ | gc.TFLOAT64: 869 a = ppc64.AFADD 870 871 case OSUB_ | gc.TINT8, 872 OSUB_ | gc.TUINT8, 873 OSUB_ | gc.TINT16, 874 OSUB_ | gc.TUINT16, 875 OSUB_ | gc.TINT32, 876 OSUB_ | gc.TUINT32, 877 OSUB_ | gc.TPTR32, 878 OSUB_ | gc.TINT64, 879 OSUB_ | gc.TUINT64, 880 OSUB_ | gc.TPTR64: 881 a = ppc64.ASUB 882 883 case OSUB_ | gc.TFLOAT32: 884 a = ppc64.AFSUBS 885 886 case OSUB_ | gc.TFLOAT64: 887 a = ppc64.AFSUB 888 889 case OMINUS_ | gc.TINT8, 890 OMINUS_ | gc.TUINT8, 891 OMINUS_ | gc.TINT16, 892 OMINUS_ | gc.TUINT16, 893 OMINUS_ | gc.TINT32, 894 OMINUS_ | gc.TUINT32, 895 OMINUS_ | gc.TPTR32, 896 OMINUS_ | gc.TINT64, 897 OMINUS_ | gc.TUINT64, 898 OMINUS_ | gc.TPTR64: 899 a = ppc64.ANEG 900 901 case OAND_ | gc.TINT8, 902 OAND_ | gc.TUINT8, 903 OAND_ | gc.TINT16, 904 OAND_ | gc.TUINT16, 905 OAND_ | gc.TINT32, 906 OAND_ | gc.TUINT32, 907 OAND_ | gc.TPTR32, 908 OAND_ | gc.TINT64, 909 OAND_ | gc.TUINT64, 910 OAND_ | gc.TPTR64: 911 a = ppc64.AAND 912 913 case OOR_ | gc.TINT8, 914 OOR_ | gc.TUINT8, 915 OOR_ | gc.TINT16, 916 OOR_ | gc.TUINT16, 917 OOR_ | gc.TINT32, 918 OOR_ | gc.TUINT32, 919 OOR_ | gc.TPTR32, 920 OOR_ | gc.TINT64, 921 OOR_ | gc.TUINT64, 922 OOR_ | gc.TPTR64: 923 a = ppc64.AOR 924 925 case OXOR_ | gc.TINT8, 926 OXOR_ | gc.TUINT8, 927 OXOR_ | gc.TINT16, 928 OXOR_ | gc.TUINT16, 929 OXOR_ | gc.TINT32, 930 OXOR_ | gc.TUINT32, 931 OXOR_ | gc.TPTR32, 932 OXOR_ | gc.TINT64, 933 OXOR_ | gc.TUINT64, 934 OXOR_ | gc.TPTR64: 935 a = ppc64.AXOR 936 937 // TODO(minux): handle rotates 938 //case CASE(OLROT, TINT8): 939 //case CASE(OLROT, TUINT8): 940 //case CASE(OLROT, TINT16): 941 //case CASE(OLROT, TUINT16): 942 //case CASE(OLROT, TINT32): 943 //case CASE(OLROT, TUINT32): 944 //case CASE(OLROT, TPTR32): 945 //case CASE(OLROT, TINT64): 946 //case CASE(OLROT, TUINT64): 947 //case CASE(OLROT, TPTR64): 948 // a = 0//???; RLDC? 949 // break; 950 951 case OLSH_ | gc.TINT8, 952 OLSH_ | gc.TUINT8, 953 OLSH_ | gc.TINT16, 954 OLSH_ | gc.TUINT16, 955 OLSH_ | gc.TINT32, 956 OLSH_ | gc.TUINT32, 957 OLSH_ | gc.TPTR32, 958 OLSH_ | gc.TINT64, 959 OLSH_ | gc.TUINT64, 960 OLSH_ | gc.TPTR64: 961 a = ppc64.ASLD 962 963 case ORSH_ | gc.TUINT8, 964 ORSH_ | gc.TUINT16, 965 ORSH_ | gc.TUINT32, 966 ORSH_ | gc.TPTR32, 967 ORSH_ | gc.TUINT64, 968 ORSH_ | gc.TPTR64: 969 a = ppc64.ASRD 970 971 case ORSH_ | gc.TINT8, 972 ORSH_ | gc.TINT16, 973 ORSH_ | gc.TINT32, 974 ORSH_ | gc.TINT64: 975 a = ppc64.ASRAD 976 977 // TODO(minux): handle rotates 978 //case CASE(ORROTC, TINT8): 979 //case CASE(ORROTC, TUINT8): 980 //case CASE(ORROTC, TINT16): 981 //case CASE(ORROTC, TUINT16): 982 //case CASE(ORROTC, TINT32): 983 //case CASE(ORROTC, TUINT32): 984 //case CASE(ORROTC, TINT64): 985 //case CASE(ORROTC, TUINT64): 986 // a = 0//??? RLDC?? 987 // break; 988 989 case OHMUL_ | gc.TINT64: 990 a = ppc64.AMULHD 991 992 case OHMUL_ | gc.TUINT64, 993 OHMUL_ | gc.TPTR64: 994 a = ppc64.AMULHDU 995 996 case OMUL_ | gc.TINT8, 997 OMUL_ | gc.TINT16, 998 OMUL_ | gc.TINT32, 999 OMUL_ | gc.TINT64: 1000 a = ppc64.AMULLD 1001 1002 case OMUL_ | gc.TUINT8, 1003 OMUL_ | gc.TUINT16, 1004 OMUL_ | gc.TUINT32, 1005 OMUL_ | gc.TPTR32, 1006 // don't use word multiply, the high 32-bit are undefined. 1007 OMUL_ | gc.TUINT64, 1008 OMUL_ | gc.TPTR64: 1009 // for 64-bit multiplies, signedness doesn't matter. 1010 a = ppc64.AMULLD 1011 1012 case OMUL_ | gc.TFLOAT32: 1013 a = ppc64.AFMULS 1014 1015 case OMUL_ | gc.TFLOAT64: 1016 a = ppc64.AFMUL 1017 1018 case ODIV_ | gc.TINT8, 1019 ODIV_ | gc.TINT16, 1020 ODIV_ | gc.TINT32, 1021 ODIV_ | gc.TINT64: 1022 a = ppc64.ADIVD 1023 1024 case ODIV_ | gc.TUINT8, 1025 ODIV_ | gc.TUINT16, 1026 ODIV_ | gc.TUINT32, 1027 ODIV_ | gc.TPTR32, 1028 ODIV_ | gc.TUINT64, 1029 ODIV_ | gc.TPTR64: 1030 a = ppc64.ADIVDU 1031 1032 case ODIV_ | gc.TFLOAT32: 1033 a = ppc64.AFDIVS 1034 1035 case ODIV_ | gc.TFLOAT64: 1036 a = ppc64.AFDIV 1037 1038 case OSQRT_ | gc.TFLOAT64: 1039 a = ppc64.AFSQRT 1040 } 1041 1042 return a 1043 } 1044 1045 const ( 1046 ODynam = 1 << 0 1047 OAddable = 1 << 1 1048 ) 1049 1050 func xgen(n *gc.Node, a *gc.Node, o int) bool { 1051 // TODO(minux) 1052 1053 return -1 != 0 /*TypeKind(100016)*/ 1054 } 1055 1056 func sudoclean() { 1057 return 1058 } 1059 1060 /* 1061 * generate code to compute address of n, 1062 * a reference to a (perhaps nested) field inside 1063 * an array or struct. 1064 * return 0 on failure, 1 on success. 1065 * on success, leaves usable address in a. 1066 * 1067 * caller is responsible for calling sudoclean 1068 * after successful sudoaddable, 1069 * to release the register used for a. 1070 */ 1071 func sudoaddable(as obj.As, n *gc.Node, a *obj.Addr) bool { 1072 // TODO(minux) 1073 1074 *a = obj.Addr{} 1075 return false 1076 }